#![allow(non_upper_case_globals)]

use chrono::Datelike;
use types::DateTrait;

pub mod types;
mod year_2024;
mod year_2025;

/// 获得现在的时候戳 8位数字
/// "年月日" => 20230109
/// (现在日期, 现rh 在时间)
pub fn get_today() -> i64 {
    let now = chrono::Local::now();
    now.year() as i64 * 10000 + now.month() as i64 * 100 + now.day() as i64
}
#[test]
fn test_get_today() {
    assert_eq!(get_today(), 20241225);
}

/// date: 20240101_i64, 20240101_i32, NaiveDate, NaiveDateTime
/// 是否是工作日
pub fn is_work_day(date: impl types::DateTrait) -> bool {
    let date = date.date();
    let is_work = date.weekday().number_from_monday() < 6;
    if !is_work {
        return false;
    }
    let date_i64 = date.ymd();
    if year_2025::RecentHSHoliday.contains(&date_i64) {
        return false;
    }
    if year_2024::RecentHSHoliday.contains(&date_i64) {
        return false;
    }
    true
}

#[test]
fn test_is_work_day() {
    use chrono::NaiveDate;

    // 2024年元旦节
    assert_eq!(is_work_day(20240101), false);
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2024, 01, 01).unwrap()), false); // NaiveDate
    assert_eq!(is_work_day(20240102), true);
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2024, 01, 02).unwrap()), true);

    // 2024年周末
    assert_eq!(is_work_day(20241221), false);
    // NaiveDate
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2024, 12, 21).unwrap()), false);
    assert_eq!(is_work_day(20241222), false);
    // NaiveDate
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2024, 12, 22).unwrap()), false);
    assert_eq!(is_work_day(20241223), true);
    // NaiveDate
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2024, 12, 23).unwrap()), true);

    // 2025年元旦节
    assert_eq!(is_work_day(20250101), false);
    // NaiveDate
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2025, 01, 01).unwrap()), false);
    assert_eq!(is_work_day(20250102), true);
    // NaiveDate
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2025, 01, 02).unwrap()), true);

    // 2025年国庆节
    assert_eq!(is_work_day(20251001), false);
    // NaiveDate
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2025, 10, 01).unwrap()), false);
    assert_eq!(is_work_day(20251006), false);
    // NaiveDate
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2025, 10, 06).unwrap()), false);
    assert_eq!(is_work_day(20251008), false);
    // NaiveDate
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2025, 10, 08).unwrap()), false);
    assert_eq!(is_work_day(20251009), true);
    // NaiveDate
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2025, 10, 09).unwrap()), true);

    // 2025年周末
    assert_eq!(is_work_day(20251220), false);
    // NaiveDate
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2025, 12, 20).unwrap()), false);
    assert_eq!(is_work_day(20251221), false);
    // NaiveDate
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2025, 12, 21).unwrap()), false);
    assert_eq!(is_work_day(20251222), true);
    //NaiveDate
    assert_eq!(is_work_day(NaiveDate::from_ymd_opt(2025, 12, 22).unwrap()), true);
}

/// 现在是否工作时间
/// befor_time: 交易开始时间(时, 分)，after_time: 交易结束时间(时, 分)
pub fn is_work_time_now(befor_time: (u32, u32), after_time: (u32, u32)) -> bool {
    let now = chrono::Local::now();
    let time = now.time();
    let r = is_work_day(now.naive_local());
    if r {
        time >= chrono::NaiveTime::from_hms_opt(befor_time.0, befor_time.1, 0).unwrap() && time <= chrono::NaiveTime::from_hms_opt(after_time.0, after_time.1, 0).unwrap()
    } else {
        r
    }
}
#[test]
fn test_is_work_time_now() {
    // 现在时间： 2024-12-25 13:30:00
    assert_eq!(is_work_time_now((14, 0), (15, 30)), false);
    assert_eq!(is_work_time_now((8, 30), (22, 30)), true);
}

pub fn is_work_day_now() -> bool {
    let now = chrono::Local::now();
    is_work_day(now.naive_local())
}

#[test]
fn test_work_date_now() {
    assert_eq!(is_work_day_now(), true);
}

/// 获得交易日
/// after_time: 当天交易结束时间(时, 分)
/// 如果当天是交易日，返回当天；如果当天超过 after_time 交易时间，返回下一个交易日
/// 如果当天不是交易日，返回下一个交易日
/// 如果当天是周末，返回下一个交易日
pub fn get_trade_day(after_time: (u32, u32)) -> i64 {
    let now = chrono::Local::now();
    let date = now.naive_local();
    let date_i64 = date.ymd();
    if is_work_day(date) {
        if date.time() <= chrono::NaiveTime::from_hms_opt(after_time.0, after_time.1, 0).unwrap() {
            return date_i64;
        }
    }
    let mut i = 1;
    loop {
        let next_date = date + chrono::Duration::days(i);
        let next_date_i64 = next_date.ymd();
        if is_work_day(next_date) {
            return next_date_i64;
        }
        i += 1;
    }
}
#[test]
fn test_get_trade_day() {
    // 现在时间： 2024-12-25 13:30:00
    assert_eq!(get_trade_day((15, 30)), 20241226);
    assert_eq!(get_trade_day((11, 30)), 20241226);
    assert_eq!(get_trade_day((15, 30)), 20241225);
}

/// 获得当前交易日
/// 如果当天是交易日，返回当天；如果当天不是交易日，返回下一个交易日
pub fn get_trade_day_now() -> i64 {
    let now = chrono::Local::now();
    let date = now.naive_local();
    let mut i = 0;
    loop {
        let next_date = date + chrono::Duration::days(i);
        let next_date_i64 = next_date.ymd();
        if is_work_day(next_date) {
            return next_date_i64;
        }
        i += 1;
    }
}
#[test]
fn test_get_trade_day_now() {
    // 现在时间： 2024-12-25 13:30:00
    assert_eq!(get_trade_day_now(), 20241225);
}

/// 获得行情日期: 如果今天行情已经启动，返回今天；如果今天行情未启动，返回上一个交易日
/// start_time: 交易开始时间(时, 分)
/// 如果当天是交易日，返回当天；如果当天小于该交易时间，返回上一个交易日
/// 如果当天不是交易日，返回上一个交易日
pub fn get_market_day(start_time: (u32, u32)) -> i64 {
    let now = chrono::Local::now();
    let date = now.naive_local();
    let date_i64 = date.ymd();
    if is_work_day(date) {
        if date.time() >= chrono::NaiveTime::from_hms_opt(start_time.0, start_time.1, 0).unwrap() {
            return date_i64;
        }
    }
    let mut i = -1;
    loop {
        let next_date = date + chrono::Duration::days(i);
        let next_date_i64 = next_date.ymd();
        if is_work_day(next_date) {
            return next_date_i64;
        }
        i -= 1;
    }
}
#[test]
fn test_get_market_day() {
    // 现在时间： 2024-12-25 15:30:00
    assert_eq!(get_market_day((11, 50)), 20241225);
    assert_eq!(get_market_day((16, 30)), 20241224);
    assert_eq!(get_market_day((16, 30)), 20241224);
}

/// 获得输入的值交易日的上一个交易日
/// 如果输入的值是交易日，返回此交易的上一个交易日；如果当天不是交易日，返回上一个交易日的上一个交易日
/// v: 前几个交易日
pub fn get_trade_day_offset(date: i64, mut offset: i64) -> i64 {
    let mut i = 1;
    if offset == 0 {
        i = 0;
    }
    let offset_action = offset < 0;
    let date = chrono::NaiveDate::from_ymd_opt((date / 10000) as i32, ((date / 100) % 100) as u32, (date % 100) as u32).unwrap();
    loop {
        let offset_date = if offset_action { date - chrono::Duration::days(i) } else { date + chrono::Duration::days(i) };
        if is_work_day(offset_date) {
            if offset < 0 {
                offset += 1;
            } else if offset > 0 {
                offset -= 1;
            }
            if offset == 0 {
                return offset_date.ymd();
            }
        }
        i += 1;
    }
}
#[test]
fn test_get_trade_day_offset() {
    // 2024-12-25 start
    assert_eq!(get_trade_day_offset(20241225, 0), 20241225);
    assert_eq!(get_trade_day_offset(20241225, -1), 20241224);
    assert_eq!(get_trade_day_offset(20241225, -2), 20241223);
    // 2024-12-22 and 2024-12-21 is a weekend; is skip
    assert_eq!(get_trade_day_offset(20241225, -3), 20241220);
    assert_eq!(get_trade_day_offset(20241225, -4), 20241219);
    assert_eq!(get_trade_day_offset(20241225, -5), 20241218);
    assert_eq!(get_trade_day_offset(20241225, -6), 20241217);
    assert_eq!(get_trade_day_offset(20241225, -7), 20241216);
    // 2024-12-15 and 2024-12-14 is a holiday; is skip
    assert_eq!(get_trade_day_offset(20241225, -8), 20241213);
    assert_eq!(get_trade_day_offset(20241225, -9), 20241212);
    assert_eq!(get_trade_day_offset(20241225, -10), 20241211);

    // 2024-12-22 start
    assert_eq!(get_trade_day_offset(20241222, 0), 20241223);
    assert_eq!(get_trade_day_offset(20241222, -1), 20241220);
    assert_eq!(get_trade_day_offset(20241222, -2), 20241219);
    assert_eq!(get_trade_day_offset(20241222, -3), 20241218);

    // 2024-12-20 start
    assert_eq!(get_trade_day_offset(20241220, 0), 20241220);
    // 2024-12-21 and 2024-12-22 is a weekend; is skip
    assert_eq!(get_trade_day_offset(20241220, 1), 20241223);
    assert_eq!(get_trade_day_offset(20241220, 2), 20241224);
    assert_eq!(get_trade_day_offset(20241220, 3), 20241225);
    assert_eq!(get_trade_day_offset(20241220, 4), 20241226);

    // 2024-12-21 start
    assert_eq!(get_trade_day_offset(20241221, 0), 20241223);
    assert_eq!(get_trade_day_offset(20241221, 1), 20241223);
    assert_eq!(get_trade_day_offset(20241221, 2), 20241224);
    assert_eq!(get_trade_day_offset(20241221, 3), 20241225);
    assert_eq!(get_trade_day_offset(20241221, 4), 20241226);
    assert_eq!(get_trade_day_offset(20241221, 5), 20241227);
    // 2024-12-28 and 2024-12-29 is a weekend; is skip
    assert_eq!(get_trade_day_offset(20241221, 6), 20241230);
    assert_eq!(get_trade_day_offset(20241221, 7), 20241231);
    // 2025-01-01 is a holiday; is skip
    assert_eq!(get_trade_day_offset(20241221, 8), 20250102);
    assert_eq!(get_trade_day_offset(20241221, 9), 20250103);
    // 2025-01-04 and 2025-01-05 is a weekend; is skip
    assert_eq!(get_trade_day_offset(20241221, 10), 20250106);

    // 2024-12-25 start
    assert_eq!(get_trade_day_offset(20241225, 0), 20241225);
    assert_eq!(get_trade_day_offset(20241225, 1), 20241226);
    assert_eq!(get_trade_day_offset(20241225, 2), 20241227);
    // 2024-12-28 and 2024-12-29 is a weekend; is skip
    assert_eq!(get_trade_day_offset(20241225, 3), 20241230);
}
